﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using ContentPipeline;

namespace Alex_s_Dream_The_Toy_World
{
    public class AnimationRenderComponent : BaseComponent
    {
        /// <summary>
        /// List of Models with name of action
        /// </summary>
        public Dictionary<string, Model> ModelList
        {
            get { return modelList; }
            set { modelList = value; }
        }
        private Dictionary<string, Model> modelList;

        private string currentAction = "";

        public string CurrentAction
        {
            get { return currentAction; }
            set 
            {
                if (ModelList.ContainsKey(value))
                {
                    currentAction = value;

                    // Look up our custom skinning information.
                    SkinningData skinningData = ModelList[CurrentAction].Tag as SkinningData;

                    if (skinningData == null)
                        throw new InvalidOperationException
                            ("This model does not contain a SkinningData tag.");

                    // Create an animation player, and start decoding an animation clip.
                    animationPlayer = new AnimationPlayer(skinningData);

                    AnimationClip clip = skinningData.AnimationClips[currentAction];

                    animationPlayer.StartClip(clip);

                    currentModel = ModelList[CurrentAction];
                }
                else
                {
                    CurrentAction = "";
                }
            }
        }

        Model currentModel;
        AnimationPlayer animationPlayer;

        /// <summary>
        /// Create a render component. All rendering info for an entity comes from here.
        /// </summary>
        /// <param name="parent">Entity this component will be attached to</param>
        public AnimationRenderComponent(BaseEntity parent)
            : base(parent)
        {
            ActivateComponent();

            ModelList = new Dictionary<string, Model>();
        }

        /// <summary>
        /// Loads an entity's model
        /// </summary>
        /// <param name="modelPath">File path to the model file</param>
        public void LoadModel(string action, string modelPath)
        {
            if (action == "" || action == null)
            {
                throw new InvalidOperationException
                    ("Action can't be empty or null");
            }

            this.modelList.Add(action, this.parentEntity.Game.AnimationModelLoader.LoadAnimationModel(modelPath));

            if (CurrentAction == "")
            {
                CurrentAction = action;
            }
        }

        public void RemoveModel(string action)
        {
            this.ModelList.Remove(action);

            if (CurrentAction == action)
            {
                CurrentAction = "";
            }
        }

        /// <summary>
        /// Allows the game to run logic.
        /// </summary>
        public override void Update(GameTime gameTime)
        {
            animationPlayer.Update(gameTime.ElapsedGameTime, true, Matrix.Identity);

            base.Update(gameTime);
        }

        public override void QueryForSkinnedModelChunks(ref RenderPassDesc desc)
        {
            this.QueryForChunks(ref desc);
        }

        public override void QueryForChunks(ref RenderPassDesc desc)
        {
            if (desc.Type == RenderPassType.Skinned)
            {
                SkinnedModelChunk chunk;
                chunk = this.parentEntity.Game.Graphics.AllocateSkinnedModelChunk();

                GraphicsDevice device = this.parentEntity.Game.Graphics.Device;

                float aspectRatio = (float)device.Viewport.Width /
                                    (float)device.Viewport.Height;

                Matrix[] bones = animationPlayer.GetSkinTransforms();
                for (int i = 0; i < bones.Length; i++)
                {
                    bones[i] *=
                          this.parentEntity.Rotation //Computes the rotation (Y)
                        * Matrix.CreateScale(this.parentEntity.Scale) //Applys the scale
                        * Matrix.CreateWorld(this.parentEntity.Position, Vector3.Forward, Vector3.Up); //Apply the translation
                }
                chunk.bones = bones;

                chunk.currentModel = currentModel;

                chunk.view = desc.RenderCamera.ViewMatrix;

                chunk.projection = desc.RenderCamera.ProjectionMatrix;

                // Compute camera matrices.
                /*chunk.view = Matrix.CreateTranslation(0, -40, 0) *
                              Matrix.CreateRotationY(MathHelper.ToRadians(cameraRotation)) *
                              Matrix.CreateRotationX(MathHelper.ToRadians(cameraArc)) *
                              Matrix.CreateLookAt(new Vector3(0, 0, -cameraDistance),
                                                  new Vector3(0, 0, 0), Vector3.Up);*/

                /*chunk.projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4,
                                                                        aspectRatio,
                                                                        1,
                                                                        10000);*/
            }
        }

        /// <summary>
        /// Handles a message sent to this component.
        /// </summary>
        /// <param name="message">Message to be handled</param>
        /// <returns>True, if handled, otherwise false</returns>
        public override bool ExecuteMessage(IMessage message)
        {
            return false;
        }
    }
}
